#include <time.h>
#include <dirent.h>
#include "../inc/m_modbus_tml.h"

// 全局上下文实例
extern m_modbus_ctx_t g_modbus_ctx;

/**
 * @brief 从设备读取标识（ID）：通过Modbus标准功能码0x2B（读取设备标识）
 * @param ctx Modbus通信上下文
 * @param dev_id 输出设备标识（长度DEVICE_ID_LEN）
 * @return 成功返回0，失败返回-1
 */
static int read_dev_id(modbus_t *ctx, char *dev_id) {
    if (!ctx || !dev_id) return -1;

    uint8_t resp[32];
    int resp_len;
    // 功能码0x2B，子功能码0x01（读取设备标识），数据长度0x0008（8字节）
    int req_len = modbus_build_request_basis(
            ctx, MODBUS_FC_DEVICE_ID, 0x0001, 0x0008, NULL, resp, &resp_len
    );

    if (req_len <= 0 || modbus_send(ctx, resp, req_len) <= 0) return -1;
    memset(resp, 0, sizeof(resp));
    if (modbus_receive(ctx, resp) <= 0) return -1;

    // 解析设备标识（响应数据段第4-11字节为设备ID，按需调整偏移）
    strncpy(dev_id, (char *)&resp[7], DEVICE_ID_LEN-1);
    dev_id[DEVICE_ID_LEN-1] = '\0';
    return 0;
}

/**
 * @brief 匹配设备配置模板（通过设备ID）
 * @param dev_id 设备标识
 * @return 成功返回模板指针，失败返回NULL
 */
static modbus_device_template_t *match_device_template(const char *dev_id) {
    if (!dev_id) return NULL;

    pthread_mutex_lock(&g_modbus_ctx.scan_mutex);
    for (int i = 0; i < g_modbus_ctx.template_cnt; i++) {
        if (strcmp(g_modbus_ctx.templates[i].dev_id, dev_id) == 0) {
            pthread_mutex_unlock(&g_modbus_ctx.scan_mutex);
            return &g_modbus_ctx.templates[i];
        }
    }
    pthread_mutex_unlock(&g_modbus_ctx.scan_mutex);
    return NULL;
}

/**
 * @brief 创建设备通信上下文（独立于全局上下文，避免冲突）
 * @param dev 设备信息
 * @param template 配置模板
 * @return 成功返回modbus_t*，失败返回NULL
 */
static modbus_t *create_dev_ctx(modbus_online_dev_t *dev, modbus_device_template_t *template) {
    modbus_t *ctx = NULL;
    modbus_config_t *global_cfg = &g_modbus_ctx.config;

    // 根据设备模式创建上下文
    if (dev->mode == MODBUS_MODE_RTU) {
        ctx = modbus_new_rtu(
                global_cfg->serial_dev,
                global_cfg->baudrate,
                global_cfg->parity,
                global_cfg->data_bits,
                global_cfg->stop_bits
        );
        if (ctx) modbus_set_slave(ctx, dev->dev_id.slave_addr);
    } else {
        ctx = modbus_new_tcp(dev->dev_id.tcp_ip, dev->tcp_port);
    }

    if (!ctx) return NULL;

    // 使用模板配置（优先）或全局配置
    int timeout = template ? template->timeout : global_cfg->timeout;
    int retry = template ? template->retry_cnt : global_cfg->retry_cnt;
    modbus_set_response_timeout(ctx, 0, timeout * 1000);
    return ctx;
}

/**
 * @brief 从连接池查找设备节点
 * @param dev 设备信息
 * @return 成功返回节点指针，失败返回NULL
 */
static conn_pool_node_t *find_conn_node(modbus_online_dev_t *dev) {
    if (!dev) return NULL;

    pthread_mutex_lock(&g_modbus_ctx.conn_pool.pool_mutex);
    for (int i = 0; i < g_modbus_ctx.conn_pool.node_cnt; i++) {
        conn_pool_node_t *node = &g_modbus_ctx.conn_pool.nodes[i];
        if (node->dev_info.mode != dev->mode) continue;

        if (node->dev_info.mode == MODBUS_MODE_RTU &&
            node->dev_info.dev_id.slave_addr == dev->dev_id.slave_addr) {
            pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);
            return node;
        } else if (node->dev_info.mode == MODBUS_MODE_TCP &&
                   strcmp(node->dev_info.dev_id.tcp_ip, dev->dev_id.tcp_ip) == 0) {
            pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);
            return node;
        }
    }
    pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);
    return NULL;
}

/**
 * @brief 加载设备配置模板（从模板文件）
 */
int m_modbus_load_templates(void) {
    FILE *fp = fopen(TEMPLATE_FILE_PATH, "r");
    if (!fp) {
        fprintf(stderr, "Failed to open template file: %s\n", TEMPLATE_FILE_PATH);
        return -1;
    }

    char line[256], section[64], key[32], val[64];
    memset(section, 0, sizeof(section));
    modbus_device_template_t *curr_template = NULL;
    modbus_register_t *curr_reg = NULL;
    int reg_idx = 0;

    g_modbus_ctx.template_cnt = 0;
    memset(g_modbus_ctx.templates, 0, sizeof(modbus_device_template_t) * MAX_DEVICE_TEMPLATES);

    while (fgets(line, sizeof(line), fp)) {
        line[strcspn(line, "\n")] = '\0';
        if (line[0] == '#' || line[0] == '\0' || line[0] == ';') continue;

        // 解析模板section：[DEVICE_ID=xxx,MODE=RTU/TCP]
        if (line[0] == '[' && line[strlen(line)-1] == ']') {
            char dev_id[DEVICE_ID_LEN], mode_str[8];
            if (sscanf(line, "[DEVICE_ID=%[^,],MODE=%[^]]", dev_id, mode_str) != 2) continue;

            // 新建模板
            if (g_modbus_ctx.template_cnt >= MAX_DEVICE_TEMPLATES) break;
            curr_template = &g_modbus_ctx.templates[g_modbus_ctx.template_cnt];
            strncpy(curr_template->dev_id, dev_id, DEVICE_ID_LEN-1);
            curr_template->mode = (strcmp(mode_str, "TCP") == 0) ? MODBUS_MODE_TCP : MODBUS_MODE_RTU;
            curr_template->timeout = MODBUS_TIMEOUT;
            curr_template->retry_cnt = DEFAULT_RETRY_CNT;
            curr_template->reg_cnt = 0;
            reg_idx = 0;
            curr_reg = NULL;
            g_modbus_ctx.template_cnt++;
            continue;
        }

        if (!curr_template) continue;

        // 解析模板参数（设备级）
        if (sscanf(line, "%[^=]=%[^\n]", key, val) != 2) continue;
        if (strcmp(key, "DEV_MODEL") == 0) {
            strncpy(curr_template->dev_model, val, 31);
        } else if (strcmp(key, "TIMEOUT") == 0) {
            curr_template->timeout = atoi(val);
        } else if (strcmp(key, "RETRY_CNT") == 0) {
            curr_template->retry_cnt = atoi(val);
        }

        // 解析寄存器模板（REGx_TYPE=xxx 开始一个新寄存器）
        if (strstr(key, "REG") && strstr(key, "TYPE")) {
            if (curr_template->reg_cnt >= MAX_REG_TEMPLATE_NUM) continue;
            curr_reg = &curr_template->regs[curr_template->reg_cnt];
            memset(curr_reg, 0, sizeof(modbus_register_t));
            // 解析寄存器类型
            if (strcmp(val, "COIL") == 0) curr_reg->type = REG_TYPE_COIL;
            else if (strcmp(val, "HOLDING") == 0) curr_reg->type = REG_TYPE_HOLDING;
            else if (strcmp(val, "INPUT") == 0) curr_reg->type = REG_TYPE_INPUT;
            else if (strcmp(val, "DISCRETE") == 0) curr_reg->type = REG_TYPE_DISCRETE_INPUT;
            reg_idx = curr_template->reg_cnt;
            continue;
        }

        // 填充当前寄存器参数
        if (curr_reg) {
            if (strcmp(key, "ADDR") == 0) curr_reg->addr = atoi(val);
            else if (strcmp(key, "LEN") == 0) curr_reg->len = atoi(val);
            else if (strcmp(key, "ACCESS") == 0) curr_reg->access = (strcmp(val, "RW") == 0) ? ACCESS_READ_WRITE : ACCESS_READ_ONLY;
            else if (strcmp(key, "DESC") == 0) strncpy(curr_reg->desc, val, 63);
            else if (strcmp(key, "END") == 0) {  // 寄存器配置结束
                curr_template->reg_cnt++;
                curr_reg = NULL;
            }
        }
    }

    fclose(fp);
    printf("Loaded %d device templates\n", g_modbus_ctx.template_cnt);
    return g_modbus_ctx.template_cnt;
}

/**
 * @brief 自动配置设备（匹配模板+自动注册寄存器）
 */
int m_modbus_auto_config(modbus_online_dev_t *dev) {
    if (!dev || g_modbus_ctx.config.is_server) return -1;

    // 1. 创建临时上下文，读取设备ID
    modbus_t *tmp_ctx = create_dev_ctx(dev, NULL);
    if (!tmp_ctx) return -1;

    char dev_id[DEVICE_ID_LEN] = {0};
    int ret = -1;
    if (modbus_connect(tmp_ctx) == 0) {
        if (read_dev_id(tmp_ctx, dev_id) == 0) {
            printf("Detected device ID: %s\n", dev_id);
            // 2. 匹配配置模板
            modbus_device_template_t *template = match_device_template(dev_id);
            if (template) {
                printf("Matched template: %s (model: %s)\n", template->dev_id, template->dev_model);
                // 3. 自动注册模板中的寄存器
                for (int i = 0; i < template->reg_cnt; i++) {
                    m_modbus_register(&template->regs[i]);
                }
                ret = 0;  // 配置成功
            } else {
                printf("No template matched for device %s, use default config\n", dev_id);
                ret = 1;  // 无匹配模板，使用默认配置
            }
        }
    }

    modbus_close(tmp_ctx);
    modbus_free(tmp_ctx);
    return ret;
}

/**
 * @brief 初始化连接池
 */
static int conn_pool_init(void) {
    memset(&g_modbus_ctx.conn_pool, 0, sizeof(modbus_conn_pool_t));
    g_modbus_ctx.conn_pool.node_cnt = 0;
    g_modbus_ctx.conn_pool.heartbeat_running = 0;
    return pthread_mutex_init(&g_modbus_ctx.conn_pool.pool_mutex, NULL);
}

/**
 * @brief 自动连接设备（添加到连接池+建立连接）
 */
int m_modbus_auto_connect(modbus_online_dev_t *dev) {
    if (!dev || g_modbus_ctx.config.is_server) return -1;

    // 1. 检查是否已在连接池
    conn_pool_node_t *node = find_conn_node(dev);
    if (node) {
        if (node->status == CONN_DISCONNECTED || node->status == CONN_ABNORMAL) {
            node->status = CONN_RECONNECTING;
            node->reconnect_cnt = 0;
        } else {
            return 0;  // 已连接/连接中，无需重复操作
        }
    }

    // 2. 新增连接节点
    pthread_mutex_lock(&g_modbus_ctx.conn_pool.pool_mutex);
    if (g_modbus_ctx.conn_pool.node_cnt >= MAX_CONN_POOL_SIZE) {
        pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);
        fprintf(stderr, "Conn pool full, cannot add device\n");
        return -1;
    }

    node = &g_modbus_ctx.conn_pool.nodes[g_modbus_ctx.conn_pool.node_cnt];
    memset(node, 0, sizeof(conn_pool_node_t));
    node->dev_info = *dev;
    node->status = CONN_CONNECTING;
    node->heartbeat_fail_cnt = 0;
    node->reconnect_cnt = 0;
    pthread_mutex_init(&node->conn_mutex, NULL);

    // 3. 匹配配置模板
    char dev_id[DEVICE_ID_LEN] = {0};
    modbus_t *tmp_ctx = create_dev_ctx(dev, NULL);
    if (tmp_ctx && modbus_connect(tmp_ctx) == 0) {
        read_dev_id(tmp_ctx, dev_id);
        node->template = match_device_template(dev_id);
    }
    if (tmp_ctx) {
        modbus_close(tmp_ctx);
        modbus_free(tmp_ctx);
    }

    // 4. 建立正式连接
    node->ctx = create_dev_ctx(dev, node->template);
    if (node->ctx && modbus_connect(node->ctx) == 0) {
        node->status = CONN_CONNECTED;
        printf("Auto connected to device: %s\n",
               dev->mode == MODBUS_MODE_RTU ?
               (char[]){0} : dev->dev_id.tcp_ip);
    } else {
        node->status = CONN_RECONNECTING;
        fprintf(stderr, "Auto connect failed, enter reconnect mode\n");
    }

    g_modbus_ctx.conn_pool.node_cnt++;
    pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);
    return 0;
}

/**
 * @brief 单个设备重连逻辑
 */
static int conn_reconnect(conn_pool_node_t *node) {
    if (!node || node->reconnect_cnt >= RECONNECT_MAX) {
        node->status = CONN_ABNORMAL;
        return -1;
    }

    pthread_mutex_lock(&node->conn_mutex);
    // 释放旧上下文
    if (node->ctx) {
        modbus_close(node->ctx);
        modbus_free(node->ctx);
        node->ctx = NULL;
    }

    // 重新创建上下文并连接
    node->ctx = create_dev_ctx(&node->dev_info, node->template);
    if (node->ctx && modbus_connect(node->ctx) == 0) {
        node->status = CONN_CONNECTED;
        node->reconnect_cnt = 0;
        node->heartbeat_fail_cnt = 0;
        printf("Reconnected to device: %s\n",
               node->dev_info.mode == MODBUS_MODE_RTU ?
               (char[]){0} : node->dev_info.dev_id.tcp_ip);
        pthread_mutex_unlock(&node->conn_mutex);
        return 0;
    }

    node->reconnect_cnt++;
    node->status = CONN_RECONNECTING;
    pthread_mutex_unlock(&node->conn_mutex);
    fprintf(stderr, "Reconnect failed (count: %d), retry later\n", node->reconnect_cnt);
    return -1;
}

/**
 * @brief 设备心跳检测（发送轻量级读取命令）
 */
static int dev_heartbeat(conn_pool_node_t *node) {
    if (!node || node->status != CONN_CONNECTED) return -1;

    pthread_mutex_lock(&node->conn_mutex);
    int ret = -1;
    uint16_t dummy_val = 0;

    // 发送轻量级命令（读线圈/读离散输入，避免占用带宽）
    if (node->template && node->template->reg_cnt > 0) {
        modbus_register_t *reg = &node->template->regs[0];
        switch (reg->type) {
            case REG_TYPE_COIL:
                ret = modbus_read_bits(node->ctx, reg->addr, 1, &dummy_val);
                break;
            case REG_TYPE_DISCRETE_INPUT:
                ret = modbus_read_discrete_inputs(node->ctx, reg->addr, 1, &dummy_val);
                break;
            case REG_TYPE_HOLDING:
                ret = modbus_read_registers(node->ctx, reg->addr, 1, &dummy_val);
                break;
            case REG_TYPE_INPUT:
                ret = modbus_read_input_registers(node->ctx, reg->addr, 1, &dummy_val);
                break;
            default:
                break;
        }
    } else {
        // 无模板时，发送诊断命令（兼容所有设备）
        uint8_t data[] = {0x01};
        uint8_t resp[8];
        int resp_len;
        int req_len = modbus_build_request_basis(
                node->ctx, MODBUS_FC_DIAGNOSTIC, 0x0000, 0x0001, data, resp, &resp_len
        );
        ret = (req_len > 0 && modbus_send(node->ctx, resp, req_len) > 0 && modbus_receive(node->ctx, resp) > 0) ? 0 : -1;
    }

    pthread_mutex_unlock(&node->conn_mutex);
    return ret;
}

/**
 * @brief 心跳监控线程（循环检测所有连接，触发重连/自动断开）
 */
static void *heartbeat_thread_func(void *arg) {
    (void)arg;
    printf("Heartbeat monitor started (interval: %d sec)\n", HEARTBEAT_INTERVAL);

    while (g_modbus_ctx.conn_pool.heartbeat_running) {
        pthread_mutex_lock(&g_modbus_ctx.conn_pool.pool_mutex);
        for (int i = 0; i < g_modbus_ctx.conn_pool.node_cnt; i++) {
            conn_pool_node_t *node = &g_modbus_ctx.conn_pool.nodes[i];

            // 跳过已断开/异常设备
            if (node->status == CONN_DISCONNECTED || node->status == CONN_ABNORMAL) continue;

            // 心跳检测
            if (dev_heartbeat(node) == 0) {
                node->heartbeat_fail_cnt = 0;  // 心跳成功，重置失败计数
            } else {
                node->heartbeat_fail_cnt++;
                printf("Heartbeat failed for device %s (count: %d)\n",
                       node->dev_info.mode == MODBUS_MODE_RTU ?
                       (char[]){0} : node->dev_info.dev_id.tcp_ip, node->heartbeat_fail_cnt);

                // 心跳失败阈值触发：重连或自动断开
                if (node->heartbeat_fail_cnt >= HEARTBEAT_RETRY) {
                    if (node->status == CONN_CONNECTED) {
                        node->status = CONN_RECONNECTING;
                        conn_reconnect(node);  // 触发重连
                    } else if (node->status == CONN_RECONNECTING && node->reconnect_cnt >= RECONNECT_MAX) {
                        // 重连失败，自动断开
                        m_modbus_auto_disconnect(&node->dev_info);
                        printf("Auto disconnect device %s (reconnect failed)\n",
                               node->dev_info.mode == MODBUS_MODE_RTU ?
                               (char[]){0} : node->dev_info.dev_id.tcp_ip);
                    }
                }
            }
        }
        pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);

        // 心跳间隔
        sleep(HEARTBEAT_INTERVAL);
    }

    printf("Heartbeat monitor stopped\n");
    pthread_exit(NULL);
}

/**
 * @brief 启动心跳监控线程
 */
int m_modbus_heartbeat_start(void) {
    if (g_modbus_ctx.conn_pool.heartbeat_running) return -1;

    g_modbus_ctx.conn_pool.heartbeat_running = 1;
    if (pthread_create(&g_modbus_ctx.conn_pool.heartbeat_thread, NULL, heartbeat_thread_func, NULL) != 0) {
        fprintf(stderr, "Create heartbeat thread failed\n");
        g_modbus_ctx.conn_pool.heartbeat_running = 0;
        return -1;
    }
    return 0;
}

/**
 * @brief 自动断开设备（释放连接资源）
 */
int m_modbus_auto_disconnect(modbus_online_dev_t *dev) {
    if (!dev) return -1;

    conn_pool_node_t *node = find_conn_node(dev);
    if (!node) return -1;

    pthread_mutex_lock(&g_modbus_ctx.conn_pool.pool_mutex);
    pthread_mutex_lock(&node->conn_mutex);

    // 释放通信上下文
    if (node->ctx) {
        modbus_close(node->ctx);
        modbus_free(node->ctx);
        node->ctx = NULL;
    }

    // 标记断开状态
    node->status = CONN_DISCONNECTED;
    node->heartbeat_fail_cnt = 0;
    node->reconnect_cnt = 0;

    pthread_mutex_unlock(&node->conn_mutex);
    pthread_mutex_unlock(&g_modbus_ctx.conn_pool.pool_mutex);

    printf("Auto disconnected device: %s\n",
           dev->mode == MODBUS_MODE_RTU ?
           (char[]){0} : dev->dev_id.tcp_ip);
    return 0;
}

/**
 * @brief 获取设备连接状态
 */
int m_modbus_get_conn_status(modbus_online_dev_t *dev) {
    conn_pool_node_t *node = find_conn_node(dev);
    if (!node) return -1;
    return node->status;
}